# -*- coding: utf-8 -*-
# @Time    : 2024/7/5 14:43
# @Author  : yujiahao
# @File    : 06_fastapi_query_str_validation.py
# @description:查询参数和字符串校验
from typing import Union, List

from fastapi import FastAPI, Query
from pydantic.v1 import Required

app = FastAPI()


# todo 1、额外的校验 ,q的值可选，但是如果闯入的话不能超过50个字符，这里需要导入Query
@app.get("/items/")
async def read_items(q: Union[str, None] = Query(
    default='我是默认值', min_length=3, max_length=50, pattern="^yujiahao$"
)):
    '''
    使用Query 来限制传入的字符，可以设置默认值，一般校验参数，以及正则
    具有默认值还会使该参数成为可选参数。
    这个指定的正则表达式通过以下规则检查接收到的参数值：

    - ^：以该符号之后的字符开头，符号之前没有字符。
    - fixedquery: 值精确地等于 fixedquery。
    - $: 到此结束，在 fixedquery 之后没有更多字符。
    如果需要这个是必要的值可以直接指定加限制条件：
    q:str = Query( min_length=3, max_length=50)
    '''
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results


# todo 2、使用省略号(...)声明必需参数

@app.get("/ids/")
async def read_ids(q: str = Query(default=..., min_length=3, max_length=50)):
    '''
    如果你之前没见过 ... 这种用法：它是一个特殊的单独值，它是 Python 的一部分并且被称为「省略号」。
    Pydantic 和 FastAPI 使用它来显式的声明需要一个值。

    '''
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results


# todo 3、使用 Query 作为默认值
@app.get("/id/")
async def read_id(q: Union[str, None] = Query(default=None, max_length=50)):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results


# todo 4、使用Pydantic中的Required代替省略号(...)
@app.get("/")
async def read(q: str = Query(default=Required, min_length=3)):
    '''
    请记住，在大多数情况下，当你需要某些东西时，可以简单地省略 default 参数，因此你通常不必使用 ... 或 Required
    [导这个模块]from pydantic.v1 import Required
    '''
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results


# todo 5、查询参数列表 / 多个值

@app.get("/items_list/")
# async def read_items_list(q: Union[List[str], None] = Query(default=None)):
async def read_items_list(q: list = Query(default=[])):
    '''
    - 可以http://localhost:8000/items_list/?q=[1,2,w,3,e,4,r]调用
    - 也可以http://localhost:8000/items/?q=foo&q=bar
    - 要声明类型为 list 的查询参数，如上所示，你需要显式地使用 Query，否则该参数将被解释为请求体。
    - list 代替 List [str] =》async def read_items(q: list = Query(default=[])):
        - 请记住，在这种情况下 FastAPI 将不会检查列表的内容。
        - 例如，List[int] 将检查（并记录到文档）列表的内容必须是整数(注意类型)。但是单独的 list 不会。
    '''
    query_items = {"q": q}
    return query_items


# todo 5、声明更多元数据


@app.get("/item_title/")
async def read_items(
        q: Union[str, None] = Query(default=None, title="参数格式说明",
                                    description="这里参数使用-不符合python命名格式，但是还是要用，可以是试用alias说明一下",
                                    alias='item-query',
                                    min_length=3,
                                    # 如果不喜欢这个参数，但是又不得不保留一段时间，可以用下面不展示以弃用
                                    deprecated=True
                                    ),
):
    '''
    不同的工具对 OpenAPI 的支持程度可能不同。
    【title】【description】
     - http://127.0.0.1:8000/docs看不到title ，能看到description
     - http://127.0.0.1:8000/redoc 都可以
     - 其中一些可能不会展示所有已声明的额外信息，尽管在大多数情况下，缺少的这部分功能已经计划进行开发。

    【 别名参数】假设你想要查询参数为 item-query。

     - 像这样：http://127.0.0.1:8000/items/?item-query=foobaritems
     - 但是 item-query 不是一个有效的 Python 变量名称。
     - 最接近的有效名称是 item_query。
     - 但是你仍然要求它在 URL 中必须是 item-query...
     - 这时你可以用 alias 参数声明一个别名，该别名将用于在 URL 中查找查询参数值

    【总结】
        你可以为查询参数声明额外的校验和元数据。\n
        - 通用的校验和元数据：
            - alias
            - title
            - description
            - deprecated   /ˈdeprəkeɪtɪd/
        - 特定于字符串的校验：
            - min_length
            - max_length
            - regex
    '''
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results
